﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Transactions;
using Microsoft.Practices.Unity;
using Wyn.PMS.Common.Utils;
using Wyn.PMS.Entity.Entities;
using Wyn.PMS.Entity.IDataAccess;

namespace Wyn.PMS.Test.Cache
{
    partial class RecuseNightAudit
    {
        private IUnityContainer container = UnityContainerService.GetContainer();

        private string _hotelId;
        private string _hotelName;
        private DateTime _bizDay;
        private DateTime _endBizDay;

        private RecuseNightAudit()
        {
        }

        public RecuseNightAudit(string hotelId,string hotelName)
        {
            _hotelId = hotelId;
            _hotelName = hotelName;
        }

        public void Recuse()
        {
            IAccountRepository accountRepository = container.Resolve<IAccountRepository>();

            var transactionOptions = new System.Transactions.TransactionOptions();

            transactionOptions.IsolationLevel = System.Transactions.IsolationLevel.ReadUncommitted;

            bool isContinue = true;

            bool changeValidCount=false;

            while (isContinue)
            {
                Console.Write("\r\n 请输入要刷新夜审数据的营业日,譬如2012-3-6 ：");

                string arg = Console.ReadLine();

                var args = arg.Split(',');

                if (DateTime.TryParse(args[0], out _bizDay))
                {
                    _bizDay = _bizDay.Date;

                    if (args.Length>1 && DateTime.TryParse(args[1], out _endBizDay))
                    {
                        _endBizDay = _endBizDay.Date;
                    }

                    if(args.Length>2)
                    {
                        bool.TryParse(args[2], out changeValidCount);
                    }
                }
                else
                {
                    continue;
                }

                if (_bizDay >= DateTime.Today || _endBizDay >= DateTime.Today)
                {
                    Console.WriteLine("输入的营业日不能大于当前日期");
                    continue;
                }

                Console.Write("请问是否确认刷新 {0} 营业日 {1}{2} 的数据(Y/N)？",_hotelName,_bizDay.ToShortDateString(),_endBizDay!=default(DateTime)?" - "+ _endBizDay.ToShortDateString():string.Empty);

                string yesOrNo = Console.ReadKey().KeyChar.ToString().ToUpper();

                if (yesOrNo.ToUpper() == "Y") isContinue = false;
            }

            IRoomTypeRepository roomTypeRepository = container.Resolve<IRoomTypeRepository>();

            IOrderRepository orderRepository = container.Resolve<IOrderRepository>();

            string asX = EnumHelper.GetCode(AccountStatus.X);

            IList<RoomType> roomTypes = new List<RoomType>();

            using (var scope = new System.Transactions.TransactionScope(System.Transactions.TransactionScopeOption.Required, transactionOptions))
            {
                roomTypes = roomTypeRepository.BatchFind(_hotelId, r => r.HotelID == _hotelId && r.IsValid == true);
                scope.Complete();
            }

            var tempDate = _bizDay;

            _endBizDay = _endBizDay < _bizDay ? _bizDay : _endBizDay;

            while (tempDate <= _endBizDay)
            {
                Console.WriteLine("\r\n开始刷新 {0} 数据。\r\n", tempDate.ToShortDateString());

                //科目汇总
                //只做营业日等于今天的账
                Expression<Func<Account, bool>> accountExp =
                    r => r.HotelID == _hotelId
                         && r.BizDay == tempDate
                         && r.Status != asX
                         && r.IsStrike == false;

                IList<Account> notRollAccounts = new List<Account>();

                using (var scope =new System.Transactions.TransactionScope(System.Transactions.TransactionScopeOption.Required,transactionOptions))
                {
                    //今日 产生 未过租的子账单
                    notRollAccounts = accountRepository.BatchFind(_hotelId, accountExp);
                    scope.Complete();
                }

                //刷新科目汇总
                //RecuseLedgerTotal(tempDate, notRollAccounts);

                //刷新经营分析
                RecuseAnalysis(tempDate, notRollAccounts, roomTypes, orderRepository, transactionOptions, changeValidCount);

                //刷酒店结余
                //RecuseHotelRemain(tempDate, notRollAccounts, transactionOptions);

                tempDate = tempDate.AddDays(1);
            }
        }

        private void RecuseLedgerTotal(DateTime bizDay, IList<Account> notRollAccounts)
        {
            Console.WriteLine("刷新科目汇总中，请稍候......");

            FixLedgerTotal fixTotal = new FixLedgerTotal();
           
            //非冲 非滚账 进 科目汇总
            fixTotal.Total(_hotelId, bizDay, notRollAccounts);

            Console.WriteLine("完成刷新 {0} 科目汇总表数据！\r\n",bizDay.ToShortDateString());
        }

        private void RecuseAnalysis(DateTime bizDay, IList<Account> notRollAccounts,IList<RoomType> roomTypes, IOrderRepository orderRepository,System.Transactions.TransactionOptions transactionOptions,bool changeValidCount)
        {
            Console.WriteLine("刷新经营分析中，请稍候......");

            string os_R = EnumHelper.GetCode(OrderStatus.R);

            string os_X = EnumHelper.GetCode(OrderStatus.X);

            //在住 今日退房的
            Expression<Func<Order, bool>> orderExp = o => o.HotelID == _hotelId && o.Status != os_R && o.Status != os_X
                && ( (o.CheckInBizDay<=bizDay && ( o.CheckOutBizDay>bizDay ||o.CheckOutBizDay==null))
                ||o.CheckInBizDay==bizDay);

            IList<string> path = new List<string>() { typeof(PriceDetail).Name };

            //全日住过的 过夜的订单
            IList<Order> fullDayOrders = new List<Order>();

            using (var scope = new System.Transactions.TransactionScope(System.Transactions.TransactionScopeOption.Required, transactionOptions))
            {
                fullDayOrders = orderRepository.BatchIncludeFind(_hotelId, orderExp, path).ToList();

                scope.Complete();
            }
            //全部夜审账涉及的
            IList<Order> allRollOrders = GetAllRollOrders(notRollAccounts, fullDayOrders, orderRepository);

            IList<Order> rollAccountOrders = GetRollAccountOrders(notRollAccounts, fullDayOrders, orderRepository, _hotelId);
            
            IDictionary<string, decimal> rtRoomFeeAccounts = SumRoomFeeAccounts(notRollAccounts, rollAccountOrders, roomTypes);
            
            FixAnalysis fix = new FixAnalysis();

            //非冲 非滚账 进 科目汇总
            fix.Analysis(_hotelId, bizDay, notRollAccounts, rtRoomFeeAccounts, roomTypes, allRollOrders,fullDayOrders, changeValidCount);

            Console.WriteLine("完成刷新 {0} 经营分析表数据！\r\n", bizDay.ToShortDateString());
        }

        private void RecuseHotelRemain(DateTime bizDay, IList<Account> notRollAccounts, System.Transactions.TransactionOptions transactionOptions)
        {
            Console.WriteLine("刷新酒店结余中，请稍候......");

            //华沙店的房间总价值：5520
            //decimal hotelAllRoomPrice = 5520;

            FixHotelRemain.RefreshHotelRemain(_hotelId, bizDay, notRollAccounts, transactionOptions);

            Console.WriteLine("完成刷新 {0} 酒店结余数据！\r\n", bizDay.ToShortDateString());

        }

        private IList<Order> GetAllRollOrders(IList<Account> notRollAccounts, IList<Order> fullDayOrders, IOrderRepository orderRepository)
        {
            var transactionOptions = new System.Transactions.TransactionOptions();

            transactionOptions.IsolationLevel = System.Transactions.IsolationLevel.ReadUncommitted;

            var notRollAccountRootIds = notRollAccounts.Select(o => o.AccountRootID).Distinct();

            var fullDayOrderIds= fullDayOrders.Select(o => o.OrderID);
            
            var otherOrderIds = notRollAccountRootIds.Where(a => !fullDayOrderIds.Contains(a));

            IList<Order> allOrders = fullDayOrders.Where(a=>fullDayOrderIds.Contains(a.OrderID)).ToList();

            if (otherOrderIds.Any())
            {
                using (var scope =new TransactionScope(System.Transactions.TransactionScopeOption.Required,transactionOptions))
                {
                    var otherOrders = orderRepository.BatchFind(_hotelId, o => otherOrderIds.Contains(o.OrderID));

                    allOrders = allOrders.Union(otherOrders).ToList();

                    scope.Complete();
                }
            }

            return allOrders;
        }

        private IList<Order> GetRollAccountOrders(IList<Account> notRollAccounts, IList<Order> allOrders, IOrderRepository orderRepository, string hotelId)
        {
            var transactionOptions = new System.Transactions.TransactionOptions();

            transactionOptions.IsolationLevel = System.Transactions.IsolationLevel.ReadUncommitted;
            //获取去重的OrderIdS
            var notRollOrderIds = notRollAccounts.Select(o => o.CreateOrderID).Distinct();

            IList<Order> rollRoomTypeOrders = new List<Order>();

            IList<string> otherOrderIds = new List<string>();

            foreach (var orderId in notRollOrderIds)
            {
                var order = allOrders.FirstOrDefault(o => o.OrderID == orderId);

                if (order == null)
                {
                    otherOrderIds.Add(orderId);
                }
                else
                {
                    rollRoomTypeOrders.Add(order);
                }
            }

            if (otherOrderIds.Any())
            {
                IList<Order> otherOrders = new List<Order>();

                using (var scope = new System.Transactions.TransactionScope(System.Transactions.TransactionScopeOption.Required, transactionOptions))
                {
                    otherOrders = orderRepository.BatchFind(hotelId, o => otherOrderIds.Contains(o.OrderID));

                    scope.Complete();
                }

                rollRoomTypeOrders = rollRoomTypeOrders.Union(otherOrders).ToList();
            }

            return rollRoomTypeOrders;
        }

        private IDictionary<string, decimal> SumRoomFeeAccounts(IList<Account> notRollAccounts, IList<Order> rollRoomTypeOrders, IList<RoomType> roomTypes)
        {
            IDictionary<string, decimal> rtRoomFee = new Dictionary<string, decimal>();

            string CIT_HR = EnumHelper.GetCode(CheckInType.HR), CIT_DR = EnumHelper.GetCode(CheckInType.DR);

            foreach (var roomtype in roomTypes)
            {
                //o.CheckInType!=EnumHelper.GetCode(CheckInType.HR) && o.CheckInType!=EnumHelper.GetCode(CheckInType.DR) 
                IEnumerable<string> roomTypeOrderIds = rollRoomTypeOrders.Where(o =>o.RoomTypeID == roomtype.RoomTypeID).Select(o => o.OrderID);

                decimal receipts = notRollAccounts.Where(a => roomTypeOrderIds.Contains(a.CreateOrderID)
                                           && !a.IsStrike
                                           && a.CheckInType != CIT_HR
                                           && a.CheckInType != CIT_DR
                                           && a.LedgerParentCode == LedgerCode.客房收入
                                           && a.LedgerCode != LedgerCode.全日租
                                           && a.LedgerCode != LedgerCode.半日租)
                                           .Sum(o => o.Balance);

                rtRoomFee.Add(roomtype.RoomTypeID, receipts);
            }

            return rtRoomFee;
        }

    }

}
